package com.ftpserver;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.Channel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class FileServerStartup {

    private ServerSocketChannel serverSocketChannel;

    private Selector selector;

    private static ByteBuffer buffer = ByteBuffer.allocateDirect(FileConfig.BUFFER_SIZE);

    private static Map<Channel, Client> clients = new HashMap<Channel, Client>();

    private static Long startTime = System.currentTimeMillis();

    public FileServerStartup() {
        try {
            init();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void init() throws Exception {
        serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);
        selector = Selector.open();
    }

    /**
     * @throws Exception
     */
    public void start() throws Exception {
        if (serverSocketChannel == null || selector == null) {
            System.out.println("serverSocketChannel or selector is null");
            return;
        }
        serverSocketChannel.socket().bind(new InetSocketAddress(FileConfig.PORT), 1024);
        System.out.println("系统启动结束");
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        handleIO();
    }

    private void handleIO() throws Exception {
        //没有实践就阻塞这
        while (selector.select() > 0) {
            startTime = System.currentTimeMillis();
            System.out.println(startTime+",开始轮询数据");
            handleKey(selector.selectedKeys().iterator());
            System.out.println(startTime+",轮询数据结束");

        }


    }

    /**
     * 事件循环处理
     *
     * @param iterator
     */
    private void handleKey(Iterator<SelectionKey> iterator) {
        while (iterator.hasNext()) {
            SelectionKey key = iterator.next();
            iterator.remove();
            if (key.isAcceptable()) {
                handleAccept(key);
            } else if (key.isReadable()) {
                handleRead(key);
            } else if (key.isWritable()) {
                handleWrite(key);
            }
        }
    }

    private void handleWrite(SelectionKey key)  {
        Client client = clients.get(key.channel());
        try {
            if (null != client) {
                client.write();
                if (client.getFileTranStatus() == FileTranStatus.FILE_END) {
                    client.close();
                } else {
                    key.channel().register(selector, SelectionKey.OP_READ);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 处理读取事件
     * 当Selector检测到读取事件时，调用此方法来处理
     *
     * @param key SelectionKey对象，表示已就绪的通道
     */
    private void handleRead(SelectionKey key) {
        // 根据SelectionKey获取对应的Client对象
        Client client = clients.get(key.channel());
        try {
            // 检查Client对象是否有效
            if (null != client) {
                // 调用Client的read方法来读取数据
                client.read();
                if(client.getFileTranStatus()==FileTranStatus.FILE_NAME_LEN
                        ||client.getFileTranStatus()==FileTranStatus.FILE_NAME
                        ||client.getFileTranStatus()==FileTranStatus.FILE_CONTENT_LEN){
                    client.getSocketChannel().register(selector, SelectionKey.OP_READ);
                }else if(client.getFileTranStatus()==FileTranStatus.FILE_CONTENT
                        ||client.getFileTranStatus()==FileTranStatus.FILE_END){
                    client.getSocketChannel().register(selector, SelectionKey.OP_WRITE);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private void handleAccept(SelectionKey key)  {
        ServerSocketChannel  serverchannel = (ServerSocketChannel) key.channel();
        try{
            SocketChannel socketchannel = serverchannel.accept();
            if(socketchannel != null){
                socketchannel.configureBlocking(false);
                socketchannel.register(selector, SelectionKey.OP_READ);
                Client client = new Client();
                client.setSocketChannel(socketchannel);
                clients.put(socketchannel, client);
            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }

}